﻿using System;
using System.Runtime.InteropServices;
using System.Text;

namespace GPLib
{

    internal static class WinNative
    {

        [DllImport( "user32.dll" )]
        [return: MarshalAs( UnmanagedType.Bool )]
        internal static extern unsafe bool GetKeyboardState( byte* lpKeyState );

        [DllImport( "user32.dll" )]
        [return: MarshalAs( UnmanagedType.Bool )]
        internal static extern unsafe bool SetKeyboardState( byte* lpKeyState );

        [DllImport( "user32.dll", CharSet = CharSet.Auto, SetLastError = true )]
        internal static extern unsafe uint SendInput( uint cInputs, Input* inputs, int cbSize );

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        internal static extern ushort VkKeyScan( char key );

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        internal static extern short GetAsyncKeyState( int vKey ); //use ( int )System.Windows.Forms.Keys.virtualKey

        [DllImport( "user32.dll", CharSet = CharSet.Auto )]
        internal static extern short GetKeyState( int vKey ); //use ( int )System.Windows.Forms.Keys.virtualKey

        [DllImport( "msvcrt.dll", EntryPoint = "memset", CallingConvention = CallingConvention.Cdecl, SetLastError = false )]
        internal static extern unsafe void* memset( void* dest, int val, int cbsize );

        [DllImport( "user32", SetLastError = true )]
        internal static extern int GetKeyNameText( int lParam, StringBuilder lpString, int cchSize );

        //[DllImport( "user32.dll", SetLastError = false )]
        //private static extern UIntPtr GetMessageExtraInfo();

        internal enum VkMods
        {
            VkShift = 0x10,
            VkControl = 0x11,
            VkMenu = 0x12,
            VkCapital = 0x14     //caps lock
        }

        internal enum InputType
        {
            Mouse = 0,          //uses InputUnion.mi
            Keyboard = 1,       //uses InputUnion.ki
            Hardware = 2        //uses InputUnion.hi
        }

        internal enum KbFlags : uint
        {
            KeyeventfNone = 0x0000,
            KeyeventfExtendedkey = 0x0001,      //If specified, the scan code was preceded by a prefix byte that has the value 0xE0 (224).
            KeyeventfKeyup = 0x0002,            //If specified, the key is being released. If not specified, the key is being pressed.
            KeyeventfUnicode = 0x0004,          //If specified, the system synthesizes a VK_PACKET keystroke. The wVk parameter must be zero.
                                                //Can ONLY be used with KeyeventfKeyup or KeyeventfNone
            KeyeventfScancode = 0x0008          //If specified, wScan identifies the key and wVk is ignored. 
        }

        [StructLayout( LayoutKind.Sequential )]
        internal struct Keybdinput
        {
            internal ushort wVk;                //1 - 254 Virtual Key Code
            internal ushort wScan;              //hardware scan code for the key: if UNICODE wScan specifies a Unicode character to be sent
            internal uint dwFlags;              //KBFlags
            internal uint time;                 //use 0 to let system specify the time (in ms)
            internal UIntPtr dwExtraInfo;       //additional value, typically NULL but can use GetMessageExtraInfo from WinAPI to fill that out
        }


        [StructLayout( LayoutKind.Sequential )]
        private struct Mouseinput
        {
            readonly int dx;
            readonly int dy;
            readonly uint mouseData;
            readonly uint dwFlags;
            readonly uint time;
            readonly UIntPtr dwExtraInfo;
        }

        [StructLayout( LayoutKind.Sequential )]
        private struct Hardwareinput
        {
            readonly uint uMsg;
            readonly ushort wParamL;
            readonly ushort wParamH;
        }

        [StructLayout( LayoutKind.Explicit )]
        internal struct InputUnion
        {
            [FieldOffset( 0 )]
            readonly Mouseinput mi;
            [FieldOffset( 0 )]
            internal Keybdinput ki;
            [FieldOffset( 0 )]
            readonly Hardwareinput hi;
        }

        [StructLayout( LayoutKind.Sequential )]
        internal struct Input
        {
            internal uint type;
            internal InputUnion iu;
        }

    }
}
